延續昨日的練習,Nodejs 中 Mongoose 本身有驗證機制,因此了解框架內部含有的安全機制,也是開發者需要了解的內容。
NoSQL 注入攻擊的原理類似於 SQL 注入,攻擊者可以利用應用程式中對使用者輸入的信任,注入惡意的查詢運算子,操縱資料庫查詢邏輯。
常見的運算子如 $ne
、$where
可以用來繞過查詢條件、執行 JavaScript 程式碼,甚至造成拒絕服務攻擊。
例如,MongoDB 中的 $where
運算子允許在查詢中執行 JavaScript 表達式。如果不對輸入進行嚴格過濾,攻擊者可以利用 $where
注入,如執行 sleep()
函數來拖慢伺服器回應,甚至對資料庫進行篡改和竊取。
此外,MongoDB 本身沒有內建的查詢參數清理功能,因此開發者需要依賴如 Mongoose 這類的 ORM 工具來處理查詢中的安全風險。
然而,如果開發者關閉了像 sanitizeFilter
這樣的防護機制,應用程式將變得更加脆弱,容易受到 NoSQL 注入攻擊的威脅。
Mongoose 6.x 引入了查詢清理機制(sanitizeFilter
),該機制會過濾掉潛在的危險運算子如 $where
。
因此,了解如何正確處理 NoSQL 查詢並防範注入攻擊,是確保應用程式安全運行的關鍵。
本課程的目標是深入探討 NoSQL 注入攻擊的原理,並透過實作範例展示如何在 MongoDB 與 Mongoose 中進行有效的防護。
本課程將涵蓋如何識別潛在的 NoSQL 安全風險,尤其是涉及 JSON 運算子注入的攻擊方式,並展示如何透過適當的輸入過濾和查詢清理機制來保護應用程式免受這類攻擊。
學員將透過以下目標達成學習成果:
$ne
和 $where
如何被濫用。sanitizeFilter
,以及如何進行輸入驗證以防範惡意注入。https://github.com/fei3363/ithelp_web_security_2024/commit/a70c2e72ad383e1fd3c21b1dc33c15f387c18d1c
productController.js
:此控制器包含了商品的查詢、篩選、以及基於價格篩選的 API。使用者輸入的 category
和 price
會進行篩選,但沒有嚴格過濾 JSON 結構,導致運算子注入風險。const Product = require('../models/product.model');
const mongoose = require('mongoose');
// 列出所有商品
exports.getAllProducts = async (req, res) => {
try {
const products = await Product.find();
res.json(products);
} catch (error) {
console.error(error);
res.status(500).send("伺服器錯誤");
}
};
// 搜尋商品
exports.searchProducts = async (req, res) => {
const query = req.query.q;
if (!query) return res.status(400).send("請提供搜尋字串");
try {
const products = await Product.find({ name: new RegExp(query, 'i') });
res.json(products);
} catch (error) {
console.error(error);
res.status(500).send("伺服器錯誤");
}
};
// 依據類別篩選商品
exports.filterProducts = async (req, res) => {
const { category } = req.query;
let filter = {};
try {
if (category.startsWith('{')) {
filter.category = JSON.parse(category);
} else {
filter.category = category;
}
const products = await Product.find(filter);
res.json(products);
} catch (error) {
console.error(error);
res.status(500).send("伺服器錯誤");
}
};
// 依據價格篩選商品
exports.filterProductsByPrice = async (req, res) => {
let { minPrice, maxPrice } = req.query;
let filter = {};
try {
if (minPrice) filter.price = { $gte: Number(minPrice) };
if (maxPrice && !maxPrice.startsWith('{')) filter.price = { ...filter.price, $lte: Number(maxPrice) };
if (maxPrice && maxPrice.startsWith('{')) {
const parsedMaxPrice = JSON.parse(maxPrice);
filter = { $where: parsedMaxPrice.$where };
}
const products = await Product.find(filter);
res.json(products);
} catch (error) {
console.error("伺服器錯誤:", error);
res.status(500).send("伺服器錯誤");
}
};
mongoose.js
:關閉 sanitizeFilter
機制以模擬不安全情境。const mongoose = require('mongoose');
mongoose.set('sanitizeFilter', false); // 關閉自動過濾,增加 NoSQL 注入風險
routes/productRoutes.js
:設定 API 路由。const express = require('express');
const router = express.Router();
const productController = require('../controllers/productController');
router.get('/list', productController.getAllProducts);
router.get('/search', productController.searchProducts);
router.get('/filter', productController.filterProducts);
router.get('/filter-by-price', productController.filterProductsByPrice);
module.exports = router;
curl http://localhost:3000/api/product/list
curl http://nodelab.feifei.tw/api/product/list
curl "http://localhost:3000/api/product/filter?category={%22$ne%22:%22%22}"
curl "http://nodelab.feifei.tw/api/product/filter?category=%7B%22$ne%22:%22%22%7D"
$where
運算子注入
curl "http://localhost:3000/api/product/filter-by-price?minPrice=100&maxPrice={%22$where%22:%22sleep(5000)%22}"
curl "http://nodelab.feifei.tw/api/product/filter-by-price?minPrice=0&maxPrice=%7B%22$where%22:%221==1%22%7D"
在本文,我們展示了如何透過 NoSQL 運算子注入來操縱 MongoDB 的查詢,並探討了如何防範此類攻擊。在現實應用中,必須謹慎處理來自使用者的輸入,並應啟用 Mongoose 的查詢清理機制以保護系統安全。
哪個運算子可以用於執行 JavaScript 表達式?
$lt
$where
$gt
$in
答案:B
解析:$where
運算子允許在 MongoDB 查詢中執行 JavaScript 表達式。
在 Mongoose 6.x 中,如何防止 JSON 運算子注入?
strictQuery
sanitizeFilter
sanitizeFilter
useNewUrlParser
答案:C
解析:sanitizeFilter
可以自動過濾掉潛在的危險運算子。
以下哪一項會導致 NoSQL 注入攻擊?
答案:B
解析:未對 JSON 運算子輸入進行驗證可能導致 NoSQL 注入攻擊。
如何安全地篩選商品的 price
?
$where
運算子答案:B
解析:應該使用數字範圍查詢,並限制使用運算子來確保安全。
關閉 sanitizeFilter
會產生什麼風險?
答案:C
解析:關閉 sanitizeFilter
會讓應用程式暴露於 NoSQL 注入攻擊中。
sanitizeFilter